package jinyilw.swing.i18n;

import jinyilw.common.SettingTools;
import jinyilw.common.log.LogTools;
import jinyilw.swing.rlaf.utils.RLafUtils;
import jinyilw.swing.visuals.Rcomp.ROptionPane;

import javax.swing.JComponent;
import javax.swing.JOptionPane;
import java.awt.Component;
import java.awt.Container;
import java.awt.Window;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Properties;
import java.util.ResourceBundle;

public final class LanguageTools
{
	public static boolean languageSettingEnable = true, needRestart = false;
	static IString switchMessage, switchTitle;
	public static String defaultPath = "jinyilw.swing.i18n.texts.texts";
	private static volatile LanguageTools defaultTools;
	private static final Locale nativeLocale = Locale.getDefault();
	private static final Locale zhLocale = Locale.CHINA;
	private static final Locale enLocale = Locale.ENGLISH;
	private static Properties zhProperties, enProperties;
	public static String languageTag = nativeLocale.toLanguageTag();

	private ResourceBundle texts, fallbackTexts;
	private Locale currentLocale;
	private ClassLoader loader;
	private String name;
	private boolean isChinese, isEnglish;

	private LanguageTools()
	{
		// zhProperties = new Properties();
		// enProperties = new Properties();
		try
		{
			fallbackTexts = ResourceBundle.getBundle(defaultPath, nativeLocale);
		} catch (Exception e)
		{
			fallbackTexts = ResourceBundle.getBundle(defaultPath, enLocale);
		}

		String language = SettingTools.getDefaultString("language", null);
		String country = SettingTools.getDefaultString("country", null);
		Locale locale;
		if (language != null)
			locale = new Locale(language, country);
		else
			locale = nativeLocale;
		setLocale(locale);
	}

	private LanguageTools(Locale locale)
	{
		// zhProperties = new Properties();
		// enProperties = new Properties();
		try
		{
			fallbackTexts = ResourceBundle.getBundle(defaultPath, nativeLocale);
		} catch (Exception e)
		{
			fallbackTexts = ResourceBundle.getBundle(defaultPath, enLocale);
		}
		setLocale(locale);
	}

	private LanguageTools(String directory, String name, Locale locale)
	{
		this.name = name;
		if (directory != null && name != null)
		{
			File appDir = new File(directory);
			try
			{
				loader = new URLClassLoader(new URL[]{appDir.toURI().toURL()},
						null);
			} catch (MalformedURLException e)
			{
				e.printStackTrace();
			}
			try
			{
				fallbackTexts = ResourceBundle.getBundle(name, nativeLocale,
						loader);
			} catch (Exception e)
			{
				fallbackTexts = ResourceBundle.getBundle(name, enLocale,
						loader);
			}
		}
		setLocale(locale);
	}

	public static void setLanguageSettingEnable(boolean isEnable)
	{
		languageSettingEnable = isEnable;
	}

	public static void setNeedRestart(boolean needRestart)
	{
		LanguageTools.needRestart = needRestart;
	}

	public static LanguageTools getDefaultTools()
	{
		if (defaultTools == null)
		{
			synchronized (LanguageTools.class)
			{
				if (defaultTools == null)
					defaultTools = new LanguageTools();
			}
		}
		return defaultTools;
	}

	public static LanguageTools getDefaultTools(Locale locale)
	{
		if (defaultTools == null)
		{
			synchronized (LanguageTools.class)
			{
				if (defaultTools == null)
					defaultTools = new LanguageTools(locale);
			}
		}
		return defaultTools;
	}

	public static LanguageTools getTools(String directory, String name,
			Locale locale)
	{
		return new LanguageTools(directory, name, locale);
	}

	public static void setDefaultLocale(Locale loc)
	{
		getDefaultTools(loc).setLocale(loc);
		SettingTools.putDefaultSettingData("language", loc.getLanguage());
		SettingTools.putDefaultSettingData("country", loc.getCountry());
	}

	public static void setToChinese()
	{
		if (!getDefaultTools().isChinese)
		{
			setDefaultLocale(zhLocale);
			executeLanguageSetting();
			if (needRestart)
				switchLanguage();
		}
	}

	public static void setToEnglish()
	{
		if (!getDefaultTools().isEnglish)
		{
			setDefaultLocale(enLocale);
			executeLanguageSetting();
			if (needRestart)
				switchLanguage();
		}
	}

	public static void switchLanguage()
	{
		if (switchMessage == null)
		{
			switchMessage = new IString("switchMessage", "部分文字需要重启应用才能切换，是否重启？",
					"Some text needs to restart the app to switch, do you want to restart?");
			switchTitle = new IString("switchTitle", "是否重启应用？",
					"do you want to restart the app?");
		}
		if (ROptionPane.showConfirmDialog(RLafUtils.getMainFrame(),
				switchMessage, switchTitle) != 0)
			return;
		RLafUtils.restartApplication();
	}

	public static String getText(String textKey, Object... replaceData)
	{
		return getDefaultTools().get(textKey, replaceData);
	}

	public static String getText(String textKey, String zhString,
			String enString)
	{
		return getDefaultTools().get(textKey, zhString, enString);
	}

	public static boolean isEnglish()
	{
		return getDefaultTools().isEnglish;
	}

	public static void saveProperties()
	{
		save(zhProperties, "texts_zh.properties");
		save(enProperties, "texts_en.properties");
	}

	public static void save(Properties p, String path)
	{
		if (p == null || path == null)
			return;
		FileOutputStream output = null;
		try
		{
			output = new FileOutputStream(path);
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		if (output != null)
		{
			try
			{
				p.store(output, "");
				output.close();
			} catch (IOException e)
			{
				e.printStackTrace();
			}
		}
	}

	public static void executeLanguageSetting()
	{
		//		for (LanguageChanger changer : languageChangers)
		//			changer.changLanguage();
		for (Window w : Window.getWindows())
			changComponentLanguage(w);
	}

	public static void changComponentLanguage(Component c)
	{
		if (c instanceof LanguageChanger)
			((LanguageChanger) c).changLanguage();
		Component[] children = null;
		if (c instanceof Container)
			children = ((Container) c).getComponents();
		if (children != null)
			for (Component child : children)
				changComponentLanguage(child);
	}

	public void setLocale(Locale loc)
	{
		if (loc == null || currentLocale == loc)
			return;
		currentLocale = loc;
		languageTag = loc.toLanguageTag().toLowerCase(Locale.ENGLISH);
		isEnglish = languageTag.contains("en");
		isChinese = languageTag.contains("zh");
		LogTools.info("设置语言：" + languageTag);
		setLocale(loc, loader);
	}

	private void setLocale(Locale loc, ClassLoader loader)
	{
		try
		{
			if (loader != null)
				texts = ResourceBundle.getBundle(name, loc, loader);
			else
				texts = ResourceBundle.getBundle(defaultPath, loc);
			JComponent.setDefaultLocale(loc);
			Locale.setDefault(loc);
		} catch (Exception e)
		{
			JOptionPane.showMessageDialog(null,
					"Fatal error: texts couldn't be loaded! Folder: /texts");
		}
	}

	public String get(String textKey, String zhString, String enString)
	{
		if (textKey == null)
			return null;
		// zhProperties.setProperty(textKey, zhString);
		// enProperties.setProperty(textKey, enString);
		if (isEnglish)
			return enString;
		return zhString;
	}

	public String get(String textKey, Object... replaceData)
	{
		try
		{
			String text = null;
			if (texts != null && texts.containsKey(textKey))
				text = texts.getString(textKey);
			if (fallbackTexts != null && text == null)
				text = fallbackTexts.getString(textKey);
			if (replaceData == null)
				return text;
			return String.format(text, replaceData);

		} catch (MissingResourceException e)
		{
			return "???";
		} catch (Exception e)
		{
			System.out.println("Text key \"" + textKey + "\" caused an error.");
			return "???";
		}
	}

	public static BufferedReader getBufferedReader_UTF8(String filename)
	{
		BufferedReader b = null;
		try
		{
			b = new BufferedReader(new InputStreamReader(
					new FileInputStream(filename), StandardCharsets.UTF_8));
		} catch (Exception ignored)
		{
		}

		if (b == null)
		{
			try
			{
				b = new BufferedReader(new InputStreamReader(
						LanguageTools.class.getResourceAsStream(filename),
						StandardCharsets.UTF_8));
			} catch (Exception ignored)
			{
			}
		}
		return b;
	}

	// Avoid cloning.
	@Override
	public Object clone() throws CloneNotSupportedException
	{
		throw new CloneNotSupportedException();
	}
}